package com.tc.property.support;

import com.tc.property.PropertyHolder;
import com.tc.property.config.ConfigLoader;
import com.tc.property.util.Constants;
import com.tc.property.util.Utils;
import com.tc.property.config.handler.DefaultContextChangedHandler;
import com.tc.property.config.handler.IConfigChangedHandler;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.PlaceholderConfigurerSupport;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

public class PropertiesUtils {

	private static Logger LOGGER = LoggerFactory.getLogger(PropertiesUtils.class);

	/**
	 * location默认值  ${spring.profiles.default}  此处区分不同环境的配置
	 */
	private static final String SYSTEM_CONFIG_DEFAULT = "classpath:/properties/application.properties,classpath:/properties/${spring.profiles.default}/application-${spring.profiles.default}.properties,classpath:/properties/${spring.profiles.active}/application-${spring.profiles.active}.properties,file:${appPropertiesFile}";

	private static final String SYSENV = "sysenv";

	/**
	 * 是否解析过venus:context
	 */
	private static volatile boolean haveResloveElement = false;

	/**
	 * 环境变量和系统变量
	 */
	private static Properties sysProps = new Properties();

	@Getter
	private static DefaultContextChangedHandler contextChangedHandler = new DefaultContextChangedHandler();

	private static PropertyPlaceholderHelper propertyPlaceholderHelper;

	public static Properties getPropsConfig(Element element) {
		try {
			init();
			PropertyHolder.addProperties(replacePlaceholders(getPropsByElement(element)));
		} catch (Exception e) {
			LOGGER.error("getPropsConfig error : " + e.getMessage());
		}

		return PropertyHolder.getProperties();
	}

	/**
	 * replacePlaceholders with sysProps
	 * 
	 * @param propsByElement
	 * @return
	 */
	private static Properties replacePlaceholders(Properties propsByElement) {
		Set<Entry<Object, Object>> entrySet = propsByElement.entrySet();
		for (Entry<Object, Object> entry : entrySet) {
			String value = (String) entry.getValue();
			if (StringUtils.hasText(value) && value.contains(Constants.ARTIFACT_ALL_PREFIX)) {
				value = propertyPlaceholderHelper.replacePlaceholders(value, sysProps);
				propsByElement.put(entry.getKey(), value);
			}
		}

		return propsByElement;
	}

	private static Properties getPropsByElement(Element element) throws IOException {
		Element venusContextElement = getVenusContextElement(element);
		if (venusContextElement != null) {
			if (!haveResloveElement) {
				return resloveElement(venusContextElement);
			} else {
				return new Properties();
			}
		} else {
			throw new RuntimeException("");
		}
	}

	private static Properties resloveElement(Element venusContextElement) throws IOException {
		haveResloveElement = true;

		String location = venusContextElement.getAttribute("location");
		if (!StringUtils.hasLength(location)) {
			location = SYSTEM_CONFIG_DEFAULT;
		}

		location = propertyPlaceholderHelper.replacePlaceholders(location, sysProps);

		//MetricRegister.registerLocations(location);

		List<String> sources = new LinkedList<String>();
		String[] locations = StringUtils.tokenizeToStringArray(location,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		if (locations != null) {
			sources.addAll(Arrays.asList(locations));
		}

		sources.add(SYSENV);

		/**
		 * 解析use-cfgcenter 默认为true，app.name is domain
		 */
		Boolean useCfgcenter = Boolean
				.valueOf(StringUtils.hasText(venusContextElement.getAttribute("use-cfgcenter")) ? venusContextElement
						.getAttribute("use-cfgcenter") : "true");
		if (useCfgcenter) {
			sources.add("cfgcenter:${app.name}:/config/${app.name}");
		}

		List<IConfigChangedHandler> configChangeHandlers = new LinkedList<IConfigChangedHandler>();
		configChangeHandlers.add(contextChangedHandler);
		return Utils.getPropsFromContext(new ConfigLoader().initConfigFromSources(sources,configChangeHandlers));
	}

	private static Element getVenusContextElement(Element element) {
		Node parentNode = element.getParentNode();
		NodeList childNodes = parentNode.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++) {
			Node node = childNodes.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (ele.getTagName().endsWith("property-placeholder")) {
					return ele;
				}
			}
		}
		return null;
	}

	private static void init() {
		if (sysProps.isEmpty()) {
			sysProps.putAll(System.getenv());
			sysProps.putAll(System.getProperties());
		}

		propertyPlaceholderHelper = new PropertyPlaceholderHelper(
				PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX,
				PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX,
				PlaceholderConfigurerSupport.DEFAULT_VALUE_SEPARATOR, true);
	}

	public static void resetHaveResloveElement() {
		haveResloveElement = false;
	}

}